﻿using System;
using System.Linq;
using System.Text.RegularExpressions;

namespace Songhay.Extensions
{
    /// <summary>
    /// Extensions of <see cref="System.String"/>.
    /// </summary>
    public static partial class StringExtensions
    {
        /// <summary>
        /// Determines whether the specified input is byte.
        /// </summary>
        /// <param name="input">The input.</param>
        /// <returns>
        /// 	<c>true</c> if the specified input is byte; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsByte(this string input)
        {
            return input.IsByte(null);
        }

        /// <summary>
        /// Determines whether the specified input is byte.
        /// </summary>
        /// <param name="input">The input.</param>
        /// <param name="secondaryTest">The secondary test.</param>
        /// <returns>
        /// 	<c>true</c> if the specified input is byte; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsByte(this string input, Predicate<byte> secondaryTest)
        {
            byte testValue;
            bool test = byte.TryParse(input, out testValue);

            if((secondaryTest != null) && test) return secondaryTest(testValue);
            else return test;
        }

        /// <summary>
        /// Determines whether the specified input is decimal.
        /// </summary>
        /// <param name="input">The input.</param>
        /// <returns>
        /// 	<c>true</c> if the specified input is decimal; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsDecimal(this string input)
        {
            return input.IsDecimal(null);
        }

        /// <summary>
        /// Determines whether the specified input is decimal.
        /// </summary>
        /// <param name="input">The input.</param>
        /// <param name="secondaryTest">The secondary test.</param>
        /// <returns>
        /// 	<c>true</c> if the specified input is decimal; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsDecimal(this string input, Predicate<decimal> secondaryTest)
        {
            decimal testValue;
            bool test = decimal.TryParse(input, out testValue);

            if((secondaryTest != null) && test) return secondaryTest(testValue);
            else return test;
        }

        /// <summary>
        /// Determines whether the specified input is integer.
        /// </summary>
        /// <param name="input">The input.</param>
        /// <returns>
        ///   <c>true</c> if the specified input is integer; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsInteger(this string input)
        {
            return input.IsInteger(null);
        }

        /// <summary>
        /// Determines whether the specified input is integer.
        /// </summary>
        /// <param name="input">The input.</param>
        /// <param name="secondaryTest">The secondary test.</param>
        /// <returns>
        ///   <c>true</c> if the specified input is integer; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsInteger(this string input, Predicate<int> secondaryTest)
        {
            int testValue;
            bool test = int.TryParse(input, out testValue);

            if((secondaryTest != null) && test) return secondaryTest(testValue);
            else return test;
        }

        /// <summary>
        /// Determines whether the specified input is long.
        /// </summary>
        /// <param name="input">The input.</param>
        /// <returns>
        /// 	<c>true</c> if the specified input is long; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsLong(this string input)
        {
            return input.IsLong(null);
        }

        /// <summary>
        /// Determines whether the specified input is long.
        /// </summary>
        /// <param name="input">The input.</param>
        /// <param name="secondaryTest">The secondary test.</param>
        /// <returns>
        /// 	<c>true</c> if the specified input is long; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsLong(this string input, Predicate<long> secondaryTest)
        {
            long testValue;
            bool test = long.TryParse(input, out testValue);

            if((secondaryTest != null) && test) return secondaryTest(testValue);
            else return test;
        }

        /// <summary>
        /// Converts the <see cref="String"/> into digits only.
        /// </summary>
        /// <param name="input">The input.</param>
        /// <returns></returns>
        public static string ToDigitsOnly(this string input)
        {
            var digitsOnly = new Regex(@"[^\d]");
            return digitsOnly.Replace(input, string.Empty);
        }

        /// <summary>
        /// Prepares a string to be converted to <c>int</c>.
        /// </summary>
        /// <param name="input">The input.</param>
        /// <returns></returns>
        public static string ToIntString(this string input)
        {
            return input.ToIntString("0");
        }

        /// <summary>
        /// Prepares a string to be converted to <c>int</c>.
        /// </summary>
        /// <param name="input">The input.</param>
        /// <param name="defaultValue">The default value ("0" by default).</param>
        /// <returns></returns>
        public static string ToIntString(this string input, string defaultValue)
        {
            if(input == null) return null;

            var output = defaultValue;
            var array = input.Split('.');

            if(array.Length == 0) return output;
            if(string.IsNullOrEmpty(array[0].Trim())) return output;

            output = array[0].ToDigitsOnly();
            if(string.IsNullOrEmpty(output)) return defaultValue;

            return output;
        }
        /// <summary>
        /// Converts the <see cref="System.String"/> into a numeric format for parsing.
        /// </summary>
        /// <param name="input">The input.</param>
        /// <returns>
        /// Returns a numeric string ready for integer or float parsing.
        /// </returns>
        public static string ToNumericString(this string input)
        {
            return input.ToNumericString("0");
        }

        /// <summary>
        /// Converts the <see cref="System.String"/> into a numeric format for parsing.
        /// </summary>
        /// <param name="input">The input.</param>
        /// <param name="defaultValue">The default value ("0" by default).</param>
        /// <returns>
        /// Returns a numeric string ready for integer or float parsing.
        /// </returns>
        public static string ToNumericString(this string input, string defaultValue)
        {
            if(string.IsNullOrEmpty(input)) return defaultValue;
            if(string.IsNullOrWhiteSpace(input)) return defaultValue;
            return new string(input.Trim().Where(i => char.IsDigit(i) || i.Equals('.')).ToArray());
        }
    }
}
